home *** CD-ROM | disk | FTP | other *** search
/ The Fatted Calf / The Fatted Calf.iso / Unix / CNews / Source / rna / newsrc.c < prev    next >
Encoding:
C/C++ Source or Header  |  1990-11-20  |  6.4 KB  |  309 lines

  1. /*
  2.  * newsrc file handling
  3.  */
  4.  
  5. #include "defs.h"
  6.  
  7. static char nrcname[]     = NEWSRC;
  8.  
  9. static char *rcname;        /* full pathname of .newsrc */
  10. newsrc *rc;            /* internal .newsrc */
  11. char *rcgrps;            /* subscription from .newsrc */
  12. static newsrc *lastrc;        /* last newsrc struct in list */
  13. static int rclineno;        /* current lineno in .newsrc */
  14. static bool sortrc;        /* if we should sort on output */
  15.  
  16. static newsrc *findnewsrc();
  17.  
  18. readnewsrc()
  19. {
  20.     register FILE *f;
  21.     static char option[] = "options";
  22.     char word[BUFSIZ], rest[BUFSIZ];    /* getline knows sizes */
  23.     extern char *getenv();
  24.  
  25.     if ((rcname = getenv("HOME")) == NULL)
  26.         error("No $HOME in environment.");
  27.     rcname = newstr3(rcname, "/", nrcname);
  28.     if ((f = fopen(rcname, "r")) == NULL)
  29.         return;
  30.  
  31.     rclineno = 0;
  32.     while (getline(f, word, rest))
  33.         if (CMP(word, option) == 0)
  34.             dooptions(rest);
  35.         else
  36.             dorcline(word, rest);
  37.     (void) fclose(f);
  38. }
  39.  
  40. /*
  41.  * Read a line from f, put first word into w and the rest into r.
  42.  * Discard trailing newline instead of storing it.
  43.  * This is a poor design, as w & r are unchecked for overrun.
  44.  */
  45. static
  46. getline(f, w, r)
  47. register FILE *f;
  48. char *w, *r;
  49. {
  50.     register int c;
  51.     register char *s;
  52.     register int n;
  53.  
  54.     rclineno++;
  55.     s = w;
  56.     n = BUFSIZ-1;
  57.     while ((c = getc(f)) != EOF && c != ' ' && c != '\t')
  58.         if (n > 0) {
  59.             *s++ = c;            /* stash first word */
  60.             n--;
  61.         }
  62.     *s = '\0';
  63.     if (n <= 0)
  64.         error("%s line %d too long", rcname, rclineno);
  65.  
  66.     if (c != EOF) {
  67.         s = r;
  68.         n = BUFSIZ-1;
  69.         while ((c = getc(f)) != EOF && c != '\n')
  70.             if (n > 0) {
  71.                 *s++ = c;        /* stash the rest */
  72.                 n--;
  73.             }
  74.         *s = '\0';
  75.         if (n <= 0)
  76.             error("%s line %d too long", rcname, rclineno);
  77.     }
  78.  
  79.     if (c != '\n' && c != EOF)
  80.         error("Bad format: %s line %d: %s", rcname, rclineno, w);
  81.  
  82.     return c != EOF;
  83. }
  84.  
  85. /*
  86.  * Parse s into words and simulate command line arguments with them.
  87.  */
  88. static
  89. dooptions(s)
  90. char *s;
  91. {
  92.     register char *cp;
  93.     register int argc;
  94.     register char **argv;
  95.  
  96.     cp = s;
  97.     while (isspace(*cp))
  98.         cp++;
  99.     if (!*cp)
  100.         return;
  101.  
  102.     argc = 1;
  103.     argv = (char **) myalloc(sizeof(char *));
  104.     argv[argc - 1] = cp;
  105.     while (*cp && (cp = strpbrk(cp, " \t")) != NULL) {
  106.         while (*cp == ' ' || *cp == '\t')
  107.             *cp++ = '\0';
  108.         if (*cp) {
  109.             argc++;
  110.             argv = (char **) myrealloc((char *) argv,
  111.                 argc * (int)sizeof(char *));
  112.             argv[argc - 1] = cp;
  113.         }
  114.     }
  115.     if (options(argc, argv, false))
  116.         error("Bad options: %s line %d: %s", rcname, rclineno, s);
  117.     free((char *) argv);
  118. }
  119.  
  120. /*
  121.  * Parse w & r together as a .newsrc newsgroup line.
  122.  */
  123. static
  124. dorcline(w, r)
  125. char *w, *r;
  126. {
  127.     register char lastw;
  128.     register int len;
  129.     register newsrc    *np;
  130.  
  131.     len = strlen(w);
  132.     lastw = w[len - 1];            /* save presumed colon or bang */
  133.     w[len - 1] = '\0';            /* nuke presumed colon */
  134.     while (*r == ' ' || *r == '\t')
  135.         r++;                /* skip extra whitespace */
  136.  
  137.     /* kludges, hacks, etc. for compatibility with other readers */
  138.     if (strncmp(r, "1-", sizeof "1-"-1) == 0)
  139.         r += sizeof "1-"-1;        /* skip usual `1-' */
  140.     if (*r == '\0')                /* rn's: `news.trash: ' */
  141.         r = "0";            /* fake a zero */
  142.  
  143.     if (lastw != ':' && lastw != NEGCHAR || !isdigit(*r))
  144.         error("Bad line: %s line %d: %s", rcname, rclineno, w);
  145.  
  146.     np = NEW(newsrc);
  147.     np->n_subscribe = (bool) (lastw == ':');    /* colon or bang? */
  148.     np->n_next = NIL(newsrc);
  149.     np->n_last = atoi(r);            /* stash first number only */
  150.     np->n_name = newstr(w);            /* stash n.g. name */
  151.  
  152.     if (rc == 0)
  153.         rc = np;
  154.     else
  155.         lastrc->n_next = np;
  156.     lastrc = np;
  157. }
  158.  
  159. /*
  160.  * for every group in active list, which belongs to the specified subscription
  161.  * list, and has messages to be read, call func
  162.  * if no mention in newsrc file, make new entry
  163.  */
  164. apply(alist, group, func, dolast)
  165. active *alist;
  166. char *group;
  167. applycom (*func)();
  168. bool dolast;
  169. {
  170.     register active *ap;
  171.     register newsrc *np;
  172.     register applycom act;
  173.     register bool donesome;
  174.  
  175.     donesome = false;
  176.     do {
  177.         act = stop;
  178.         for (ap = alist; ap; ap = ap->a_next) {
  179.             if (ap->a_seq == 0 || ap->a_low > ap->a_seq)
  180.                 continue;    /* empty group */
  181.             if (!ngmatch(ap->a_name, group))
  182.                 continue;
  183.             if ((np = findnewsrc(ap->a_name)) == NULL) {
  184.                 np = NEW(newsrc);
  185.                 np->n_name = newstr(ap->a_name);
  186.                 np->n_next = NULL;
  187.                 np->n_last = 0;
  188.                 np->n_subscribe = true;
  189.                 if (!rc)
  190.                     rc = np;
  191.                 else
  192.                     lastrc->n_next = np;
  193.                 lastrc = np;
  194.             }
  195.             if (!np->n_subscribe)
  196.                 continue;
  197.             /*
  198.              * if we haven't read any news for a while (or at all),
  199.              * or somehow seq got smaller (active corrupted?),
  200.              * set last read to oldest available article
  201.              */
  202.             if (ap->a_low - 1 > np->n_last || ap->a_seq < np->n_last)
  203.                 np->n_last = ap->a_low - 1;
  204.             while (np->n_last < ap->a_seq) {
  205.                 donesome = true;
  206.                 switch (act = (*func)(ap, np, false, false)) {
  207.                 case stop:        
  208.                     return;
  209.                 case next:        
  210.                     continue;
  211.                 case nextgroup:        
  212.                     break;
  213.                 case searchgroup:    
  214.                     break;
  215.                 }
  216.                 break;
  217.             }                /* while */
  218.             if (act == searchgroup)
  219.                 break;
  220.         }                    /* for */
  221.         if (act != searchgroup && dolast && donesome)
  222.             act = (*func)(NIL(active), NIL(newsrc), true, false);
  223.     } while (act == searchgroup);
  224. }
  225.  
  226. /*
  227.  * find if a newsrc entry exists,
  228.  * taking advantange of the fact that requests should be
  229.  * in the same order
  230.  *
  231.  * detect when the newsrc gets out of order
  232.  * so it can be sorted at the end of the session
  233.  */
  234. static newsrc *
  235. findnewsrc(name)
  236. register char *name;
  237. {
  238.     register newsrc *np, *start;
  239.     register bool found;
  240.     static newsrc *nextp;
  241.  
  242.     if (!rc)
  243.         return NULL;
  244.  
  245.     found = false;
  246.     np = nextp ? nextp : rc;
  247.     nextp = start = np;
  248.     do {
  249.         if (CMP(np->n_name, name) == 0) {
  250.             found = true;
  251.             break;
  252.         }
  253.         np = np->n_next;
  254.         if (!np)
  255.             np = rc;
  256.     } while (np != nextp);
  257.  
  258.     if (!found)
  259.         return NIL(newsrc);
  260.     nextp = np->n_next;
  261.     if (np != start)
  262.         sortrc = true;
  263.     return np;
  264. }
  265.  
  266. /*
  267.  * rewrite the newsrc file
  268.  */
  269. writenewsrc(alist)
  270. active *alist;
  271. {
  272.     register FILE *f;
  273.     register active    *ap;
  274.     register newsrc    *np;
  275.     register int i;
  276.     extern int usize;
  277.  
  278.     if (!rc && (!rcgrps || !*rcgrps))
  279.         return;
  280.  
  281.     signal(SIGINT, SIG_IGN);
  282.     signal(SIGQUIT, SIG_IGN);
  283.  
  284.     f = fopenf(rcname, "w");
  285.     if (rcgrps && *rcgrps)
  286.         (void) fprintf(f, "options -n %s\n", rcgrps);
  287.     if (sortrc) {
  288.         /*
  289.          * sort newsrc so next time we use it,
  290.          * history/newsrc comparisons will be faster
  291.          */
  292.         for (ap = alist; ap; ap = ap->a_next)
  293.             if (np = findnewsrc(ap->a_name))
  294.                 writengline(f, np);
  295.     } else
  296.         for (np = rc; np; np = np->n_next)
  297.             writengline(f, np);
  298.     (void) fclose(f);
  299. }
  300.  
  301. static
  302. writengline(f, np)        /* write .newsrc n.g. line in normal form on f */
  303. FILE *f;
  304. register newsrc *np;
  305. {
  306.     (void) fprintf(f, "%s%c 1-%d\n", np->n_name,
  307.         (np->n_subscribe? ':': NEGCHAR), np->n_last);
  308. }
  309.